package com.nononsenseapps.feeder.ui.base

import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.Build
import android.os.Bundle
import android.os.IBinder
import android.support.v4.media.session.MediaSessionCompat
import androidx.fragment.app.Fragment
import com.lxj.xpopup.XPopup
import com.nononsenseapps.feeder.ui.R
import com.nononsenseapps.feeder.tts.TtsService
import com.nononsenseapps.feeder.ui.qr.GenerateQRCodeActivity
import com.nononsenseapps.feeder.util.isTrue
import fr.gaulupeau.apps.Poche.tts.AbstractTtsService
import fr.gaulupeau.apps.Poche.tts.source.TextInterface
import kotlinx.coroutines.*
import timber.log.Timber
import androidx.lifecycle.lifecycleScope
import com.gitee.wsl.common.ui.ext.applicationViewModels
import com.gitee.wsl.common.ui.ext.startActivity
import com.gitee.wsl.struct.category.CategoryItemWarp
import com.nononsenseapps.feeder.cache.LocalFileCacheManager
import com.nononsenseapps.feeder.db.ARG
import com.nononsenseapps.feeder.db.entity.*
import com.nononsenseapps.feeder.db.room.*
import com.nononsenseapps.feeder.model.GlobalViewModel
import com.nononsenseapps.feeder.ui.BuildConfig
import com.nononsenseapps.feeder.ui.setting.SettingsViewModel
import com.nononsenseapps.feeder.ui.tag.*


/**
 * A fragment which is also Coroutine aware.
 *
 * All coroutines started in this fragment are linked to the Fragment's lifecycle. If the fragment
 * is destroyed, then all coroutines are cancelled. Likewise, if any of the coroutines encounter
 * an exception, that cancels the other coroutines
 */
abstract class CoroutineScopedFragment: Fragment() {

    private lateinit var mediaSessionToken: MediaSessionCompat.Token
    protected  var ttsService: AbstractTtsService?=null
    private lateinit var serviceConnection: ServiceConnection

    /*protected val globalViewModel by lazy { getGlobalViewModel() }
    protected val settingsViewModel by lazy{  getSettingsViewModel() }*/

    protected val globalViewModel by applicationViewModels<GlobalViewModel>()
    protected val settingsViewModel by applicationViewModels<SettingsViewModel>()


    protected val feedItemDao by lazy { AppDatabase.getInstance(requireActivity()).feedItemDao()}
    protected val feedDao by lazy { AppDatabase.getInstance(requireActivity()).feedDao()}
    protected val feedItemFeatureDao by lazy { AppDatabase.getInstance(requireActivity()).feedItemFeatureDao()}

    protected val feedItemTagDao by lazy { AppDatabase.getInstance(requireActivity()).feedItemTagDao()}

    protected val feedItemPreLoadItemDao by lazy { AppDatabase.getInstance(requireActivity()).feedItemPreLoadItemDao()}

    protected val localFileCacheManager by lazy { LocalFileCacheManager(requireContext(),true) }


    protected val feedItemTagRepository by lazy {
        object: AdapterItemTagRepository(globalViewModel){
            override fun listItemTags(): List<String> {
                return  getCurrentListItemTags()
            }

            override fun contextScope(): CoroutineScope = lifecycleScope
        }
    }

    protected val itemTagClickCallBack by lazy {
        object : AbstractItemTagClickCallBack() {
            override fun onItemTagClick(itemTagWap: CategoryItemWarp) {
                if(itemTagWap.isRoot) return
                //@Todo
                /*itemTagWap.item.clickCount+=1
                globalViewModel.updateFeedItemTagClickCount(itemTagWap.item.id,itemTagWap.item.clickCount)*/
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        debug().isTrue {Timber.d("${this.javaClass.simpleName}:call on onCreate ..")}
    }

    override fun onDestroy() {
        super.onDestroy()
        debug().isTrue {Timber.d("${this.javaClass.simpleName}:call on onDestroy ..")}
    }

    override fun onDestroyView() {
        super.onDestroyView()
        debug().isTrue { Timber.d("${this.javaClass.simpleName}:call on onDestroyView ..")}
    }


    override fun onResume() {
        super.onResume()
        debug().isTrue { Timber.d("${this.javaClass.simpleName}:call on resume ..")}
    }

    override fun onPause() {
        super.onPause()
        debug().isTrue { Timber.d("${this.javaClass.simpleName}:call on pause ..")}
    }

    override fun onStop() {
        debug().isTrue {  Timber.d("${this.javaClass.simpleName}:call on stop ..")}
        super.onStop()
    }

    override fun onStart() {
        super.onStart()
        debug().isTrue {  Timber.d("${this.javaClass.simpleName}:call on start ..")}
    }

    fun debug():Boolean = BuildConfig.DEBUG

    override fun onAttach(context: Context) {
        super.onAttach(context)
        debug().isTrue {  Timber.d("${this.javaClass.simpleName}:call on onAttach ..")}
    }


    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        debug().isTrue {  Timber.d("${this.javaClass.simpleName}:call on onSaveInstanceState ..")}
    }

    override fun onDetach() {
        super.onDetach()
        debug().isTrue {  Timber.d("${this.javaClass.simpleName}:call on onDetach ..")}
    }

    override fun startActivity(intent: Intent) {
        super.startActivity(intent)
        debug().isTrue {  Timber.d("${this.javaClass.simpleName}:call on startActivity ..")}
    }


    fun getCurrentListItemTags():List<String>{
        val tags= mutableSetOf<String>()
        tags.addAll(globalViewModel.createCurrentListItemsTags())
        tags.addAll(settingsViewModel.historyTags)
        return tags.toList()
    }

    @InternalCoroutinesApi
    fun popItemTagsEdit(
        id: Long,
        itemCurrentTags: List<String>,
        itemSampleTags: List<String>,
        callBack: (id: Long, tagsList: List<String>) -> Unit
    ) {
        XPopup.Builder(context).asCustom(
            ItemTagsEditDrawerPopup(
                requireContext(),
                itemTagClickCallBack = itemTagClickCallBack ,
                repository = feedItemTagRepository,
                id = id,
                _itemCurrentTags = itemCurrentTags,
                itemSampleTags = itemSampleTags,
                callBack = callBack
            )
        ).show()
    }



    protected fun changeAttentionLevel(attentionLevel:Int,f: (Int) -> Unit){
        XPopup.Builder(context).asCenterList(getString(R.string.attention_level_title), resources.getStringArray(R.array.array_attention_level_values),null,
            MAX_ATTENTION_LEVEL -attentionLevel){ index, _->
            f(MAX_ATTENTION_LEVEL -index)
        }.show()
    }

    fun generateQRCode(url:String,title:String?=null){
        val i = Intent(activity, GenerateQRCodeActivity::class.java)
        i.putExtra(ARG.LINK, url)
        title?.let { i.putExtra(ARG.TITLE, title) }
        startActivity(i)
    }

    //tts
    protected  fun initTtsServiceAndPlay(textInterface: TextInterface) {
        serviceConnection = object : ServiceConnection {
            override fun onServiceConnected(name: ComponentName, binder: IBinder) {
                Timber.d("onServiceConnected()")
                ttsService = (binder as AbstractTtsService.LocalBinder).service
                mediaSessionToken = ttsService?.mediaSessionToken!!

                ttsService!!.setTextInterface(textInterface)
            }
            override fun onServiceDisconnected(name: ComponentName) {
                Timber.d("onServiceDisconnected()")
                ttsService = null
            }
        }

        val intent = Intent(activity, TtsService::class.java)
        intent.action = AbstractTtsService.ACTION_PLAY
        requireActivity().bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            requireActivity().startForegroundService(intent)
        }else {
            requireActivity().startService(intent)
        }
    }


    protected fun ttsSpeak(textInterface: TextInterface){
        if(ttsService == null)
            initTtsServiceAndPlay(textInterface)
        else {
            ttsService!!.setTextInterface(textInterface)
            val intent = Intent()
            intent.action = AbstractTtsService.ACTION_PLAY
            ttsService!!.onStartCommand(intent, 0, 0)
        }
    }

    fun downLoadEnclosure(itemId:Long,preLoadUrl:String) {
        lifecycleScope.launch(Dispatchers.IO) {
            localFileCacheManager.startDownLoadFile(preLoadUrl,null)
        }
    }

    fun pauseDownLoadEnclosure(itemId:Long,preLoadUrl:String) {
        lifecycleScope.launch(Dispatchers.IO) {
            localFileCacheManager.pauseDownLoadFile(preLoadUrl)
        }
    }

    fun resumeDownLoadEnclosure(itemId:Long,preLoadUrl:String) {
        lifecycleScope.launch(Dispatchers.IO) {
            localFileCacheManager.resumeDownLoadFile(preLoadUrl)
        }
    }

    fun cancelDownLoadEnclosure(itemId:Long,preLoadUrl:String) {
        lifecycleScope.launch(Dispatchers.IO) {
            localFileCacheManager.cancelDownLoadFile(preLoadUrl)
        }
    }

    fun delDownLoadEnclosure(itemId:Long,preLoadUrl:String) {
        lifecycleScope.launch(Dispatchers.IO) {
            localFileCacheManager.removeDownLoadFile(preLoadUrl)
        }
    }
}

